<script setup lang="ts" name="GoodsSku">
import { GoodsInfo, Specs, SpecsValue } from '@/types/goods'
import bwPowerSet from '@/utils/power-set'

const props = defineProps<{
  goods: GoodsInfo
  skuId?: string
}>()
const emit = defineEmits<{
  (e: 'changeSku', value: string): void
}>()
// 初始化时，如果子组件传了skuId值,设置默认选中效果
const initSelectedSpec = () => {
  const initSku = props.goods.skus.find((item) => item.id === props.skuId) //根据skuId找到对应sku
  //如果存在
  if (initSku) {
    //遍历所有的规格
    props.goods.specs.forEach((item, index) => {
      // 先让其余规格都不选中--排他
      item.values.forEach((sub) => (sub.selected = false))
      // 获取到默认sku中的规格
      const value = initSku.specs[index].valueName
      // 找到value对应的规格的值选中
      const spec = item.values.find((item) => item.name === value)
      // 让规格的值默认选中
      spec!.selected = true
    })
  }
}
initSelectedSpec()

// 点击规格的值的方法
const changeSelected = (item: Specs, sub: SpecsValue) => {
  if (sub.disabled) return //如果本身状态是禁用的,就不允许点击--20cm的都没有库存
  if (sub.selected) {
    // 如果已经是选中了，取消选中
    sub.selected = false
  } else {
    // 把同级所有(包括sub)的全部取消选中--干掉所有人
    item.values.forEach((i) => {
      i.selected = false
    })
    // 复活他自己
    sub.selected = true
  }
  updateDisabledStatus() //每次点击需要重新调用按钮禁用状态的方法

  // 点击完规格值，需要将sku的id拿到，并传给父组件
  // 1. 判断规格是否全部选中
  const selectedSku = getSelectedSpec().filter((v) => v)
  // 过滤完空值，如果和specs（各种规格）的长度是相等的，说明都选上了
  if (selectedSku.length === props.goods.specs.length) {
    const key = selectedSku.join('★') //2.拼成路径字典中的属性的形式
    const [skuId] = pathMap[key] //从路径字典中查找，并得到值，把值解构出来
    emit('changeSku', skuId) //3.将得到的skuId传给父组件
  } else {
    emit('changeSku', '') //如果没有将规格全部选中,也传一个空过去,之后好判断是否能加入购物车
  }
}

// 禁用按钮
/*思路：1.把sku中库存为0的过滤掉，得到有效sku的组合
2.根据有效sku组合，得到所有的子集集合--幂集--并得出路径字典
3.查看对象里有无对应属性，没有则禁用按钮*/

// 求幂集运算---并生成路径字典
const getPathMap = () => {
  const pathMap: { [aa: string]: string[] } = {} //设一个路径字典,空对象,类型是--字符串属性名:由id组成的字符串数组
  const skus = props.goods.skus.filter((item) => item.inventory > 0) //过滤掉库存为0的skus
  skus.forEach((item) => {
    const arr = item.specs.map((sub) => sub.valueName) //遍历有效的skus,获取有效的skus下specs的valuename
    const powerSet = bwPowerSet(arr) //调用工具中的方法求幂集[]
    //   console.log(powerSet)
    //把求出来的幂集合并到一个路径字典中
    powerSet.forEach((sub) => {
      const key = sub.join('★') // 将数组改成字符串
      if (key in pathMap) {
        //判断这个字符串是否在路径字典中--因为一个中国里面,有可能会放两个id
        pathMap[key].push(item.id) //路径字典中如果已经存在此属性的话,往数组中追加
      } else {
        pathMap[key] = [item.id] //否则直接给属性赋值一个数组即可
      }
    })
  })
  return pathMap
}
const pathMap = getPathMap()
console.log(pathMap)

//获取选中的规格
const getSelectedSpec = () => {
  const arr: string[] = []
  // 遍历所有的规格
  props.goods.specs.forEach((item) => {
    const selectedItem = item.values.find((sub) => sub.selected) //将被选中的规格的值项找到
    arr.push(selectedItem ? selectedItem.name : '') //在新数组中添加,如果有被选中,就push名字,没找到就push空字符串,因为有顺序
  })
  return arr //['','中国','']
}

// 按钮的禁用状态
const updateDisabledStatus = () => {
  //遍历所有的规格
  props.goods.specs.forEach((item, index) => {
    // 遍历规格的值
    item.values.forEach((sub) => {
      const selectedSpec = getSelectedSpec() //调用选中的规格的方法,得到选中的值--数组
      // console.log(selectedSpec)
      selectedSpec[index] = sub.name //把当前需要判断的规格放到选中的数组中,如果都没选中的话,就是空
      const key = selectedSpec.filter((v) => v).join('★') //过滤掉空字符串,再用★把每一项拼起来
      //遍历规格的值
      if (key in pathMap) {
        //如果规格的值在路径字典中
        sub.disabled = false //不禁用
      } else {
        sub.disabled = true //规格的值不在路径字典中,就禁用
      }
    })
  })
}
updateDisabledStatus()
</script>
<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.name">
      <dt>{{ item.name }}</dt>
      <dd>
        <template v-for="sub in item.values" :key="sub.name">
          <img
            :class="{ selected: sub.selected, disabled: sub.disabled }"
            :src="sub.picture"
            alt=""
            v-if="sub.picture"
            :title="sub.name"
            @click="changeSelected(item, sub)"
          />
          <span
            :class="{ selected: sub.selected, disabled: sub.disabled }"
            v-else
            @click="changeSelected(item, sub)"
          >
            {{ sub.name }}
          </span>
        </template>
      </dd>
    </dl>
  </div>
</template>

<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        margin-top: 5px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 30px;
        padding: 0 20px;
        margin-top: 5px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
